package com.hyq.learn.common.util;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

/**
 * @author heyuqin
 * @date 2024/8/21 10:51
 */
public abstract class SnakeJsonUtils {

    private final static Logger LOGGER = LoggerFactory.getLogger(LowCameCaseJsonUtil.class);

    private static final ObjectMapper OBJECT_MAPPER;

    static {
        OBJECT_MAPPER = new ObjectMapper()
                .setSerializationInclusion(JsonInclude.Include.NON_NULL)
                .setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE)
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)
                .disable(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS);

        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        OBJECT_MAPPER.setTimeZone(TimeZone.getTimeZone("GMT+8"));

        OBJECT_MAPPER.registerModule(new JavaTimeModule());
    }

    public static String toJson(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (Exception e) {
            LOGGER.error("Error while serializing object to json.", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 将实体序列化为格式化的json字符串
     *
     * @param obj
     * @return
     */
    public static String toPrettyJson(Object obj) {
        try {
            return OBJECT_MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
        } catch (Exception e) {
            LOGGER.error("Error while serializing object to pretty json.", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 将实体序列化为字节json
     *
     * @param obj
     * @return
     */
    public static byte[] toBytesJson(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsBytes(obj);
        } catch (Exception e) {
            LOGGER.error("Error while serializing object to bytes json.", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 将实体序列化为json,并写入文件
     *
     * @param file
     * @param obj
     */
    public static void toJsonFile(File file, Object obj) {
        try {
            OBJECT_MAPPER.writeValue(file, obj);
        } catch (Exception e) {
            LOGGER.error("Error while serializing object to json file.", e);
            throw new RuntimeException(e);
        }
    }

    public static <T> T fromJson(String json, Class<T> valueClass) {
        try {
            return OBJECT_MAPPER.readValue(json, valueClass);
        } catch (Exception e) {
            LOGGER.error("Error while deserializing json to object.", e);
            throw new RuntimeException(e);
        }
    }

    public static <T> T fromJsonIgnoreEx(String json, Class<T> valueClass) {
        try {
            return OBJECT_MAPPER.readValue(json, valueClass);
        } catch (Exception e) {
            LOGGER.error("Error while deserializing json to object. error:{}", e.getMessage());
            return null;
        }
    }

    /**
     * 将json字节数组反序列化为实体 Note:此方法只支持简单实体类型的反序列化,如果需要反序列化为集合类型实体,使用
     * {@link #fromJson(byte[], Class, Class...)} }
     *
     * @param json
     * @param valueClass 实体类型
     * @return
     * @see JsonUtil#fromJson(byte[], Class, Class...)
     */
    public static <T> T fromJson(byte[] json, Class<T> valueClass) {
        try {
            return OBJECT_MAPPER.readValue(json, valueClass);
        } catch (Exception e) {
            LOGGER.error("Error while deserializing json to object.", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 将json字符串反序列化为泛型类型实体
     *
     * @param json
     * @param parametersFor    泛型实体类类型
     * @param parameterClasses 泛型参数类型
     * @return
     */
    public static <T> T fromJson(String json, Class<?> parametersFor, Class<?>... parameterClasses) {
        try {
            JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametrizedType(parametersFor, parametersFor, parameterClasses);
            return OBJECT_MAPPER.readValue(json, javaType);
        } catch (Exception e) {
            LOGGER.error("Error while deserializing json to collection object.", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 将json字符串反序列化为实体
     *
     * @param json
     * @param typeReference 实体对应的类型引用
     * @return
     */
    public static <T> T fromJson(String json, TypeReference<T> typeReference) {
        try {
            return OBJECT_MAPPER.readValue(json, typeReference);
        } catch (Exception e) {
            LOGGER.error("Error while deserializing json to object.", e);
            throw new RuntimeException(e);
        }
    }

    public static <T> T fromJson(byte[] json, TypeReference<T> typeReference) {
        try {
            return OBJECT_MAPPER.readValue(json, typeReference);
        } catch (Exception e) {
            LOGGER.error("Error while deserializing json to object.", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 将json字节数组反序列化为泛型类型实体
     *
     * @param json
     * @param parametersFor    泛型实体类类型
     * @param parameterClasses 泛型参数类型
     * @return
     */
    public static <T> T fromJson(byte[] json, Class<?> parametersFor, Class<?>... parameterClasses) {
        try {
            JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructParametrizedType(parametersFor, parametersFor, parameterClasses);
            return OBJECT_MAPPER.readValue(json, javaType);
        } catch (Exception e) {
            LOGGER.error("Error while deserializing json to collection object.", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 从指定的文件读取json信息,并反序列化为实体
     *
     * @param file
     * @param valueClass
     * @return
     */
    public static <T> T fromJson(File file, Class<T> valueClass) {
        try {
            return OBJECT_MAPPER.readValue(file, valueClass);
        } catch (Exception e) {
            LOGGER.error("Error while deserializing json to object from file.", e);
            throw new RuntimeException(e);
        }
    }

    public static <T> T fromJson(File file, TypeReference<T> typeReference) {
        try {
            return OBJECT_MAPPER.readValue(file, typeReference);
        } catch (Exception e) {
            LOGGER.error("Error while deserializing json to object from file.", e);
            throw new RuntimeException(e);
        }
    }

    public static <T> T fromJson(String json, TypeReference<T> typeReference, boolean ignoreEx) {
        try {
            return OBJECT_MAPPER.readValue(json, typeReference);
        } catch (Exception e) {
            LOGGER.error("Error while deserializing json to object.", e);
            if (ignoreEx) {
                return null;
            }
            throw new RuntimeException(e);
        }
    }

    public static <T> T objectTransfer(Object obj, TypeReference<T> typeReference) {
        try {
            return fromJson(toJson(obj), typeReference);
        } catch (Exception e) {
            LOGGER.error("Error while transfer a object.", e);
            throw new RuntimeException(e);
        }
    }

    public static <T> T objectTransfer(Object obj, TypeReference<T> typeReference, boolean ignoreEx) {
        try {
            return fromJson(toJson(obj), typeReference);
        } catch (Exception e) {
            LOGGER.error("Error while transfer a object.", e);
            if (ignoreEx) {
                return null;
            }
            throw new RuntimeException(e);
        }
    }

}
